/**
 * Copyright [2015] Tianfu Ma (matianfu@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * File: buddy.c
 *
 * Created on: Jun 5, 2015
 * Author: Tianfu Ma (matianfu@gmail.com)
 */

#include "../include/errno.h"
#include "../include/data_type.h"
#include "../include/alloc.h"
#include "../include/memfunc.h"
#include "alloc_init.h"
#include "cube_static.h"
static struct static_sys * static_struct;
extern struct page_index *pages;
extern BYTE * first_page;
extern struct alloc_total_struct * root_struct;


int static_init ()
{
	UINT16 start_page;
    void * curr_pointer;

	curr_pointer=get_firstpagemem_bottom(sizeof(struct static_sys));
	if(curr_pointer==NULL)
		return 	-CUBEERR_NOMEM;
	static_struct = (struct static_sys *)curr_pointer;

	Memset(static_struct,0,sizeof(*static_struct));
	start_page=get_page();
	if(start_page==0)
		return 0;
	root_struct -> empty_pages --;
	root_struct -> static_size ++;
	pages[start_page].type = STATIC_PAGE;
	static_struct->pages_num++;
	static_struct->first_page=start_page;
	static_struct->curr_page=start_page;

	return curr_pointer-page_get_addr(0);
}

void * Salloc(int size)
{
	void * addr;
	UINT16 page;
	int real_size;

	real_size=size+sizeof(UINT16);
	
	if(real_size>PAGE_SIZE)
		return 0;
	if(PAGE_SIZE-static_struct->curr_offset >real_size)
	{
		addr=first_page + static_struct->curr_page*PAGE_SIZE+static_struct->curr_offset+sizeof(UINT16);

		static_struct->curr_offset+=real_size;
		static_struct->total_size+=real_size;
	}		
	else
	{	
		page=get_page();
		if(page==0)
			return 0;
		root_struct -> empty_pages --;
		root_struct -> static_size ++;
		pages[page].priv_page=static_struct->curr_page;
		pages[static_struct->curr_page].next_page=page;
		pages[page].type = STATIC_PAGE;
		static_struct->curr_page=page;
		static_struct->pages_num++;
		addr=first_page+page*PAGE_SIZE+sizeof(UINT16);
		static_struct->curr_offset=real_size;
	}
	*(UINT16 *)(addr-sizeof(UINT16))=size;//add two bytes free

	return addr;
}
void * Salloc0(int size)
{
	void * addr = Salloc(size);
	if(addr != 0)
	{
		Memset(addr, 0, size);
	}
	return addr;
}

int Free0(void * pointer)
{
	UINT16 page;
	page = addr_get_page(pointer);
	switch(pages[page].type)
	{
		case TEMP_PAGE:
			return TFree(pointer);
		case STATIC_PAGE:
			return -CUBEERR_INVAL;
		case DYNAMIC_PAGE:
			return DFree(pointer);
		case CACHE_PAGE:
			return CFree(pointer);
		default :
			return -CUBEERR_INVAL;
	}
	return 0;
}
int Free(void * pointer)
{
	Free0(pointer);
	return 0;
}

